package com.minelx.datamicroscope.querylanguage.data;

import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.fastjson.JSONObject;

import java.util.Objects;

import static com.minelx.datamicroscope.querylanguage.data.QueryBuilder.strip;

public class CollectingField {

	private final String alias;

	private final String field;

	private final String methodName;

	private CollectingField(String alias, String field, String methodName) {
		this.alias = alias;
		this.field = field;
		this.methodName = methodName;
	}

	public String getAlias() {
		return alias;
	}

	public String getField() {
		return field;
	}

	public String getMethodName() {
		return methodName;
	}

	public JSONObject renderAggregationSpec() {
		String methodName = getMethodName();
		JSONObject spec = new JSONObject();
		spec.put("name", getAlias());
		spec.put("column", getAlias());
		spec.put("function", methodName);
		return spec;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;
		CollectingField that = (CollectingField) o;
		return alias.equals(that.alias) && field.equals(that.field);
	}

	@Override
	public int hashCode() {
		return Objects.hash(alias, field);
	}

	@Override
	public String toString() {
		return "CollectingField{" +
				"alias='" + alias + '\'' +
				", field='" + field + '\'' +
				'}';
	}

	public static CollectingField create(String fieldAlias, String field, String methodName) {
		return new CollectingField(strip(fieldAlias, "\""), field, methodName);
	}

	public static CollectingField of(SQLSelectItem sqlSelectItem) {
		return create(aliasOf(sqlSelectItem),
				parseFieldName(sqlSelectItem.getExpr()),
				parseMethodName(sqlSelectItem.getExpr()));
	}

	public static String aliasOf(SQLSelectItem sqlSelectItem) {
		if (sqlSelectItem.getAlias() == null) {
			return sqlSelectItem.toString();
		}
		return strip(sqlSelectItem.getAlias(), "\"");
	}

	private static String parseFieldName(SQLExpr fieldExpr) {
		if (fieldExpr instanceof SQLAggregateExpr) {
			return parseFieldName0(((SQLAggregateExpr) fieldExpr).getArguments().get(0));
		}
		return parseFieldName0(fieldExpr);
	}

	private static String parseFieldName0(SQLExpr fieldExpr) {
		if (fieldExpr instanceof SQLPropertyExpr) {
			return ((SQLPropertyExpr) fieldExpr).getName();
		} else if (fieldExpr instanceof SQLIdentifierExpr) {
			return ((SQLIdentifierExpr) fieldExpr).getName();
		} else {
			throw new IllegalArgumentException("unexpected type: " + fieldExpr.getClass());
		}
	}

	private static String parseMethodName(SQLExpr fieldExpr) {
		if (fieldExpr instanceof SQLAggregateExpr) {
			SQLAggregateExpr expr = (SQLAggregateExpr) fieldExpr;
			return expr.getMethodName();
		}
		return null;
	}
}
